using System;
using System.Linq;

namespace Cmc.Modbus.Base
{
    public class ModbusTcpCmd : IBytesCmd
    {
        public byte[] ReadCoilStatus(int start, int length, int id = 0, byte flag = 1)
        {
            return ReadCmd(start, length, id, flag, FunctionCode.ReadCS);
        }

        public byte[] ReadInputStatus(int start, int length, int id = 0, byte flag = 1)
        {
            return ReadCmd(start, length, id, flag, FunctionCode.ReadIS);
        }

        public byte[] ReadInputRegister(int start, int length, int id = 0, byte flag = 1)
        {
            return ReadCmd(start, length, id, flag, FunctionCode.ReadIR);
        }

        private byte[] ReadCmd(int start, int length, int id, byte flag, byte functionCode)
        {
            if (id==0)
            {
                id = start;
            }
            var idBytes = id.To2Bytes();
            var startBytes = start.To2Bytes();
            var lenthBytes = length.To2Bytes();

            byte[] cmd = new byte[]
            {
                idBytes.High,idBytes.Low,0x00,0x00,0x00,0x06,flag,
                functionCode,
                startBytes.High,startBytes.Low,
                lenthBytes.High,lenthBytes.Low
            };
            return cmd;
        }


        public byte[] ReadHoldingRegister(int start, int length, int id = 0, byte flag = 1)
        {
            return ReadCmd(start, length, id, flag, FunctionCode.ReadHR);
        }

        public byte[] WriteCoilStatus(int start, bool value, int length = 1, int id = 0, byte flag = 1)
        {
            if (id==0)
            {
                id = start;
            }
            var idBytes = id.To2Bytes();
            var startBytes = start.To2Bytes();
            HighLowBytes valueBytes = value ? new HighLowBytes() { High = 0xFF } : new HighLowBytes();

            if (length == 1) //写单个
            {
                byte[] cmd = new byte[]
                {
                idBytes.High,idBytes.Low,0x00,0x00,0x00,0x06,flag,
                FunctionCode.WriteCS,
                startBytes.High,startBytes.Low,
               valueBytes.High,valueBytes.Low
                };
                return cmd;
            }
            else
            {
                var lenthBytes = length.To2Bytes();
                byte[] cmd = new byte[]
               {
                    idBytes.High,idBytes.Low,0x00,0x00,0x00,0x09,flag,
                    FunctionCode.WriteCSs,
                    startBytes.High,startBytes.Low,
                    lenthBytes.High,lenthBytes.Low,
                    0x02,
                    valueBytes.High,valueBytes.Low
               };
                return cmd;
            }
        }

        public byte[] WriteHoldingRegister(int start, int value, int length = 1, int id = 0, byte flag = 1)
        {
            Console.WriteLine($"写入地址：{start}  写入值：{value}");

            var idBytes = id.To2Bytes();
            var startBytes = start.To2Bytes();
            HighLowBytes valueBytes = value.To2Bytes();
            if (length == 1) //写单个
            {
                byte[] cmd = new byte[]
                {
                    idBytes.High,idBytes.Low,0x00,0x00,0x00,0x06,flag,
                    FunctionCode.WriteHR,
                    startBytes.High,startBytes.Low,
                    valueBytes.High,valueBytes.Low
                };
                return cmd;
            }
            else
            {
                var lenthBytes = length.To2Bytes();
                byte[] cmd = new byte[]
                {
                    idBytes.High,idBytes.Low,0x00,0x00,0x00,0x09,flag,
                    FunctionCode.WriteHRs,
                    startBytes.High,startBytes.Low,
                    lenthBytes.High,lenthBytes.Low,
                    0x02,
                    valueBytes.High,valueBytes.Low
                };
                return cmd;
            }
        }

        public ReadDataBack ReciveDataHandle(string ip, int port, byte[] data, int startAddr=0)
        {
            ReadDataBack reciveData = new ReadDataBack()
            {
                Ip = ip,
                Port = port,
                Datas = data
            };

            reciveData.Id = OtherHelper.ByteToInt(data[1], data[0]);   //id默认为起始地址
            reciveData.StartAddr = reciveData.Id;
            reciveData.StationNumber = data[6];
            reciveData.ThisFunctionCode = data[7];
            reciveData.Length = data[8];

            if (reciveData.ThisFunctionCode == FunctionCode.ReadIS || reciveData.ThisFunctionCode == FunctionCode.ReadCS) //离散位读取
            {
                var edata = data.Skip(9).Take(reciveData.Length);
                var bits = OtherHelper.ToBitArray(edata.ToArray());
                for (int i = 0; i < bits.Count; i++)
                {
                    if (i>=ConstConfig.OnceLenth)
                    { 
                        break;
                    }
                    byte value = 0x00;
                    if (bits[i])
                    {
                        value = 0x01;
                    }
                    AddressReadValue address = new AddressReadValue(reciveData.StartAddr + i, value, 0x00);  //把id作为起始位置
                    reciveData.Addresses.Add(address.Address, address);
                }
            }
            else if (reciveData.ThisFunctionCode == FunctionCode.ReadHR || reciveData.ThisFunctionCode == FunctionCode.ReadIR) //寄存器读取
            {
                var edata = data.Skip(9).Take(reciveData.Length).ToArray();
                for (int i = 0; i + 1 < edata.Length; i = i + 2)
                {
                    if (i>=ConstConfig.OnceLenth*2)
                    {
                        break;
                    }
                    AddressReadValue address = new AddressReadValue(reciveData.StartAddr + i/2, edata[i + 1], edata[i]);  //把id作为起始位置
                    reciveData.Addresses.Add(address.Address, address);
                }
            }
            return reciveData;
        }
    }
}
